package cn.sytton.taffecloud.common.db.mybatis;

import lombok.extern.slf4j.Slf4j;
import org.apache.ibatis.cache.CacheKey;
import org.apache.ibatis.executor.Executor;
import org.apache.ibatis.mapping.BoundSql;
import org.apache.ibatis.mapping.MappedStatement;
import org.apache.ibatis.plugin.Intercepts;
import org.apache.ibatis.plugin.Invocation;
import org.apache.ibatis.plugin.Plugin;
import org.apache.ibatis.plugin.Signature;
import org.apache.ibatis.session.ResultHandler;
import org.apache.ibatis.session.RowBounds;
import org.springframework.util.StringUtils;

import java.lang.reflect.Field;

@Slf4j
@Intercepts(
	{
		@Signature(type = Executor.class, method = "query", args = {MappedStatement.class, Object.class, RowBounds.class, ResultHandler.class}),
		@Signature(type = Executor.class, method = "query", args = {MappedStatement.class, Object.class, RowBounds.class, ResultHandler.class, CacheKey.class, BoundSql.class}),
	}
)
public class ValidatorDuplicateInterceptor implements org.apache.ibatis.plugin.Interceptor {

	public Object intercept(Invocation invocation) throws Throwable {
		if (ValidatorParamsHelp.getLocalParams() != null) {
			try {
				Object[] args = invocation.getArgs();
				MappedStatement ms = (MappedStatement) args[0];
				Object parameter = args[1];
				RowBounds rowBounds = (RowBounds) args[2];
				BoundSql boundSql;
				//由于逻辑关系，只会进入一次
				if (args.length == 4) {
					//4 个参数时
					boundSql = ms.getBoundSql(parameter);
				} else {
					//6 个参数时
					boundSql = (BoundSql) args[5];
				}

				createValidateSql(boundSql);
			} catch (Exception e){
				log.error(e.getMessage(), e);
			}
		}

		return invocation.proceed();
	}

	private void createValidateSql(BoundSql boundSql) throws Throwable {
		ValidatorParams params = ValidatorParamsHelp.getLocalParams();
		String sql = boundSql.getSql();
		sql = "select * from ( "+ sql +" ) _t where ";
		StringBuilder whereSql = new StringBuilder();
		for(String name : params.getValidateField().keySet()) {
			whereSql.append(" _t.").append(name).append(" = '").append(params.getValidateField().get(name).toString()).append("'").append(" and");
		}
		if (StringUtils.hasText(params.getExcludeFieldName())) {
			whereSql.append(" _t.").append(params.getExcludeFieldName()).append(" != '").append(params.getExcludeFieldValue()).append("'");
			sql = sql + whereSql.toString();
		} else {
			sql = sql + whereSql.toString().substring(0, whereSql.toString().length() - 3); //删除最后的and
		}
		Field field = boundSql.getClass().getDeclaredField("sql");
		field.setAccessible(true);
		field.set(boundSql, sql);
	}

	public Object plugin(Object target) {
		return Plugin.wrap(target, this);
	}
}